#include "StdAfx.h"
#include "GtdDOM.h"
#include <map>
#include <vector>
#include "GtdDOMItem.h"
#include "rapidxml_utils.hpp"

#include <sstream>
using namespace cpputil;

static TCHAR N_PROJECTS[] = _T("Projects");
static TCHAR N_PROJECT[] =_T("Project");
static TCHAR N_CONTEXTS[]= _T("Contexts");
static TCHAR N_CONTEXT[] =_T("Context");
static TCHAR N_TASKENTRIES[]= _T("TaskEntries");
static TCHAR N_TAKSENTRY[]= _T("TaskEntry");
static TCHAR N_TASKITEMS[]= _T("TaskItems");
static TCHAR N_TASKITEM[] =_T("TaskItem");


using namespace rapidxml;
class GtdDOMData
{
public:
	GtdDOMData( GtdDOM* pParent):mpDOM(pParent){    }
	~GtdDOMData(){  }
	GtdDOM* mpDOM;
	
	//typedef std::map<CGuid,GtdDOMItem*> ItemMap;	
	/*GtdDOMItem* getItem(const CGuid& id)const{
		ItemMap::const_iterator itr = itemap.find(id);
		if(itr!=itemap.end())
		{
			return itr->second;
		}
		return NULL;
	}*/

	//xmldoc* getXMLDoc()const{ return mpxmlDoc; }


	
	void AddToList(GuidList& list, GtdDOMItem* newItem)
	{
		list.push_back(newItem->m_id);
		//itemap[newItem->m_id] = newItem;	
	}
	
	
	//read items
	template<class T>
	void ReadItems(GuidList& list,xmldoc* mpxmlDoc, TCHAR* SP,TCHAR* SS)
	{
		if(xmlNode pnode = mpxmlDoc->first_node(SP))//read projects
		{
			xmlNode subNode = pnode.firstChild(SS);
			while(subNode)
			{				
				T* newItem = mpDOM->allocateDOMItem<T>();
				if(newItem->readFromXMLNode(subNode))
				{
					AddToList(list,newItem);		
				}
				subNode = subNode.nextSibling(SS);
			}
		}
	}
	void read(xmldoc& doc)
	{
		
		ReadItems<GtdProject>(mProjectList,&doc, N_PROJECTS,N_PROJECT);
		ReadItems<GtdContext>(mContextList,&doc, N_CONTEXTS,N_CONTEXT);
		ReadItems<GtdTaskEntry>(mTaskEntryList,&doc, N_TASKENTRIES,N_TAKSENTRY);
		ReadItems<GtdTaskItem>(mTaskItemList,&doc, N_TASKITEMS,N_TASKITEM);
	}

	//add each items
	void AppendEach(const GuidList& itemlist,xmldoc* mpxmlDoc, TCHAR* nodeName, TCHAR* subNodeName )
	{
		xmlNode pNode = mpxmlDoc->allocate_node(node_element,nodeName);
		mpxmlDoc->append_node(pNode.mpNode);
		for(GuidList::const_iterator itr =itemlist.begin();itr!=itemlist.end();++itr)
		{
			if( GtdDOMItem* pItem = mpDOM->getItem(*itr) )
			{
				xmlNode child = pNode.createChild(subNodeName);			
				pItem->saveToXMLNode(child);
			}
		}
	}
	void save(xmldoc& doc)
	{		
		AppendEach(mProjectList,&doc,N_PROJECTS,N_PROJECT);		
		AppendEach(mContextList,&doc,N_CONTEXTS,N_CONTEXT);
		AppendEach(mTaskEntryList,&doc,N_TASKENTRIES,N_TAKSENTRY);
		AppendEach(mTaskItemList,&doc,N_TASKITEMS,N_TASKITEM);
	}
	//
	GuidList mContextList;
	GuidList mProjectList;
	GuidList mTaskEntryList;
	GuidList mTaskItemList;
protected:
	//ItemMap itemap;
	//xmldoc* mpxmlDoc;

};





GtdDOM::GtdDOM(void)
{
	m_pData = new GtdDOMData(this);
}


GtdDOM::~GtdDOM(void)
{
	Clear();
}



void GtdDOM::load( const CString& sfile )
{	
	
	try
	{
		std::basic_ifstream<TCHAR> stream(sfile.GetString(), std::ios::binary);
		if(stream)
		{
			rapidxml::file<TCHAR> fileLoad(stream);  
			TCHAR* content = fileLoad.data();  
			if(content)
			{
				Clear();
				autoptr_reset(m_pData,new GtdDOMData(this));
				xmldoc doc;
				doc.parse<0>(content);
				getData()->read(doc);		
			}
			
		}	
	
	}
	catch (rapidxml::parse_error&)
	{
	}	
	catch (CException* e)
	{
		DELETE_EXCEPTION(e);
	}
	
}




void GtdDOM::save( const CString& sfile )
{
	//return;
	try
	{
		xmldoc doc;
		getData()->save(doc);

		//save to file
#ifdef UNICODE  
		std::wofstream xml_file(sfile.GetString());  
		//xml_file.imbue(std::locale("CHS"));  
#else  
		std::ofstream xml_file(sfile.GetString());  
#endif  
		xml_file<< doc;

	}		
	catch (rapidxml::parse_error&e)
	{
		TRACE(e.what());
	}	
	catch (CException* e)
	{
		DELETE_EXCEPTION(e);
	}
	catch(...)
	{
		TRACE("Unexpected Error");
	}
	

}



void GtdDOM::AddTaskEntry( GtdTaskEntry* pEntry )
{
	getData()->AddToList(getData()->mTaskEntryList, pEntry);
}



GtdDOMItem* GtdDOM::getItem( const CGuid& gid ) const
{
	//return getData()->getItem(gid);
	for(size_t i=0;i<vAllocateItems.size();++i)
	{
		GtdDOMItem* pitem = vAllocateItems.at(i);
		if(pitem->m_id == gid )
			return pitem;
	}
	return NULL;
}



GuidList GtdDOM::GetTaskEntryList() const
{
	return m_pData->mTaskEntryList;
}

GtdTaskEntry* GtdDOM::GetTaskEntry( const CGuid& id ) const
{
	if( GtdDOMItem* pItem = getItem(id) )
	{
		return pItem->toTaskEntry();
	}
	return NULL;
}

GuidList GtdDOM::GetContextList() const
{
	return m_pData->mContextList;
}

void GtdDOM::Clear()
{
	autoptr_reset(m_pData);
	deleteVectorItem(vAllocateItems);
}

void GtdDOM::SetContextList( const GuidList& newlist )
{
	m_pData->mContextList =  newlist;
}

GuidList GtdDOM::GetContextTaskItemList( const CGuid& context ) const
{
	GuidList retlist;
	GuidList taskitemlist = m_pData->mTaskItemList;
	for(GuidList::const_iterator itr = taskitemlist.begin();itr!=taskitemlist.end();++itr)
	{
		if(GtdDOMItem* pItem = getItem(*itr) )
		{
			if(GtdTaskItem* pTaskItem = pItem->toTaskItem())
			{
				GtdTaskEntry* pEntry = pTaskItem->GetEntry();
				ASSERT(pEntry);
				if(pEntry->hasContext(context))
				{
					retlist.push_back(*itr);
				}
			}
		}
	}
	return retlist;
}

GuidList GtdDOM::GetUnContextTaskItemList() const
{
	GuidList retlist;
	GuidList taskitemlist = m_pData->mTaskItemList;
	for(GuidList::const_iterator itr = taskitemlist.begin();itr!=taskitemlist.end();++itr)
	{
		if(GtdDOMItem* pItem = getItem(*itr) )
		{
			if(GtdTaskItem* pTaskItem = pItem->toTaskItem())
			{
				GtdTaskEntry* pEntry = pTaskItem->GetEntry();
				ASSERT(pEntry);
				if(pEntry->IsContexted())
				{
					retlist.push_back(*itr);
				}
			}
		}
	}
	return retlist;
}

